package com.google.code.yargon.level;

/**
 * Form is a 3x3 area that creates a certain formation, e.g.<br><br>
 * <pre>
 * . # .       . . . 
 * # # .   or  # # #
 * . . .       . # .
 * </pre>
 * Blocks surrounding the middle block determine the form type. In above a se-corner and a s-t-cross
 * 
 * @author Mika Myllynen
 *
 */
public class Form extends Area {
	
	// Straight 
	public static final int FORM_V = 0;
	public static final int FORM_H = 1;
	
	// Corners
	public static final int FORM_C_NE = 2;
	public static final int FORM_C_SE = 3;
	public static final int FORM_C_SW = 4;
	public static final int FORM_C_NW = 5;
	
	// Crossings
	public static final int FORM_CROSS = 6;
	public static final int FORM_T_N = 7;
	public static final int FORM_T_E = 8;
	public static final int FORM_T_S = 9;
	public static final int FORM_T_W = 10;
	
	public static final int FORM_UNKNOWN = 100;

	/**
	 * Construct new empty Form
	 * 
	 */
	public Form() {
		super(3, 3);
	}
	
	/**
	 * Construct a new Form from Area
	 * @param a
	 */
	public Form(Area a) {
		super(3, 3, a.area);
	}
	
	/**
	 * Formalize a Location l, i.e. reset it's coordinates in accordance to Location center's coordinates assumed being 1,1 (center of 3*3 Area).
	 * Basically if center is at (10,10) and l is at (10,11), l's coordinates become (1,2).
	 * 
	 * @param middle
	 * @param surround
	 * @return
	 */
	public static Location formalize(Location center, Location l) {
		return new Location(l.getX() - center.getX() + 1, l.getY() - center.getY() + 1, 0);
	}
	
	/**
	 * Determine type of the formation<br><br>
	 * 
	 * Block and surrounding blocks are given binary values like this:<br><br>
	 * <pre>
	 * +---+---+---+
	 * | 1 | 2 | 4 |
	 * +---+---+---+
	 * | 8 |16 |32 |
	 * +---+---+---+
	 * |64 |128|256|          
	 * +---+---+---+
	 * </pre>
	 * Now for example formation (center block is the one we're inspecting)
	 * <pre>
	 * . # .
	 * . # #
	 * . . .
	 * </pre>
	 * Gives binary sum 2 + 32. Therefore we can check if bits 2 && 32 are set, we have a sw curve or a corner.<br>
	 * @param c list of classes (of Blocks) that are accepted as the block that creates the form.
	 * 
	 */
	public int getFormType(Class<?> ... c) {
		
		int sum = 0;
		
		// First row
		if(isOfType(0, 2, c)) {
			sum +=1;
		}
		if(isOfType(1, 2, c)) {
			sum +=2;
		}
		if(isOfType(2, 2, c)) {
			sum +=4;
		}
	
		// Second row
		if(isOfType(0, 1, c)) {
			sum +=8;
		}
		if(isOfType(1, 1, c)) {
			sum +=16;
		}
		if(isOfType(2, 1, c)) {
			sum +=32;
		}

		
		// Third row
		if(isOfType(0, 0, c)) {
			sum +=64;
		}
		if(isOfType(1, 0, c)) {
			sum +=128;
		}
		if(isOfType(2, 0, c)) {
			sum +=256;
		}
				
		// Determine type according to significant blocks (bits)
		if((sum & 2) == 2 && (sum & 8) == 8 && (sum & 32) == 32 && (sum & 128) == 128) {
			return FORM_CROSS;
		}
				
		else if((sum & 2) == 2 && (sum & 8) == 8 && (sum & 32) == 32) {
			return FORM_T_N;
		}
		
		else if((sum & 2) == 2 && (sum & 32) == 32 && (sum & 128) == 128) {
			return FORM_T_E;
		}

		else if((sum & 8) == 8 && (sum & 32) == 32 && (sum & 128) == 128) {
			return FORM_T_S;
		}
		
		else if((sum & 2) == 2 && (sum & 8) == 8 && (sum & 128) == 128) {
			return FORM_T_W;
		}
		
		else if((sum & 8) == 8 && (sum & 128) == 128) {
			return FORM_C_NE;
		}
				
		else if((sum & 2) == 2 && (sum & 8) == 8) {
			return FORM_C_SE;
		}

		else if((sum & 2) == 2 && (sum & 32) == 32) {
			return FORM_C_SW;
		}
		
		else if((sum & 32) == 32 && (sum & 128) == 128) {
			return FORM_C_NW;
		}
		
		else if(((sum & 8) == 8 && (sum & 32) == 32) || ((sum & 8) == 8) || ((sum & 32) == 32)) {
			return FORM_H;
		}
		
		else if(((sum & 2) == 2 && (sum & 128) == 128) || ((sum & 2) == 2) || ((sum & 128) == 128)) {
			return FORM_V;
		}
		return FORM_UNKNOWN;
	}
}
